package com.gearbox.core.driver.impl;

import com.gearbox.core.configuration.AsConfiguration;
import com.gearbox.core.driver.AsHandler;
import com.gearbox.core.http.HttpConfigFactory;
import com.gearbox.core.util.SdkResponseAssertion;
import com.huaweicloud.sdk.as.v1.AsClient;
import com.huaweicloud.sdk.as.v1.model.BatchRemoveInstancesOption;
import com.huaweicloud.sdk.as.v1.model.BatchRemoveScalingInstancesRequest;
import com.huaweicloud.sdk.as.v1.model.BatchRemoveScalingInstancesResponse;
import com.huaweicloud.sdk.as.v1.model.ListScalingInstancesRequest;
import com.huaweicloud.sdk.as.v1.model.ListScalingInstancesResponse;
import com.huaweicloud.sdk.as.v1.model.ScalingGroupInstance;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.PostConstruct;

@Component
public class AsHandlerImpl implements AsHandler {
    private static final Logger LOG = LoggerFactory.getLogger(AsHandlerImpl.class);

    private final AsConfiguration asConfiguration;

    private final HttpConfigFactory configFactory;

    private AsClient asClient;

    public AsHandlerImpl(AsConfiguration envConfig, HttpConfigFactory configFactory) {
        this.asConfiguration = envConfig;
        this.configFactory = configFactory;
    }

    @PostConstruct
    public void init() {
        initAsClient();
    }

    void initAsClient() {
        asClient = AsClient.newBuilder()
            .withHttpConfig(configFactory.getHttpConfig())
            .withCredential(configFactory.getBasicCredentials())
            .withEndpoint(asConfiguration.getEndpoint())
            .build();
    }

    @Override
    public List<ScalingGroupInstance> listAllScalingInstance() {
        LOG.info("list all scaling instances begin");
        List<ScalingGroupInstance> instances = new ArrayList<>();
        listScalingInstanceByPage(instances, 0, asConfiguration.getListInstanceLimit());
        LOG.info("list all scaling instances end, instances={}", instances);
        return instances;
    }

    @Override
    public Map<String, ScalingGroupInstance> getNameMapGroupInstances() {
        Map<String, ScalingGroupInstance> instanceMap = new HashMap<>();
        listAllScalingInstance().forEach(
            instance -> instanceMap.put(instance.getInstanceName().toLowerCase(Locale.ROOT), instance));
        return instanceMap;
    }

    void listScalingInstanceByPage(List<ScalingGroupInstance> instances, int startNum, int limit) {
        LOG.info("list all instances by page begin");
        ListScalingInstancesResponse listResp = asClient.listScalingInstances(
            buildListScalingInstancesRequest(startNum, limit));
        LOG.info("list all instances by page end, resp={}", listResp);
        SdkResponseAssertion.assertError(listResp, "list scaling group instance failed");
        if (listResp.getScalingGroupInstances() != null) {
            instances.addAll(listResp.getScalingGroupInstances());
        }
        if (isNeedListInstancesNextPage(listResp, instances)) {
            listScalingInstanceByPage(instances, startNum + limit, limit);
        }
    }

    ListScalingInstancesRequest buildListScalingInstancesRequest(int startNum, int limit) {
        return new ListScalingInstancesRequest().withScalingGroupId(asConfiguration.getGroup())
            .withStartNumber(startNum)
            .withLimit(limit);
    }

    boolean isNeedListInstancesNextPage(ListScalingInstancesResponse preListResp,
        List<ScalingGroupInstance> currentInstances) {
        return preListResp != null && preListResp.getScalingGroupInstances() != null
            && !preListResp.getScalingGroupInstances().isEmpty()
            && currentInstances.size() < preListResp.getTotalNumber();
    }

    @Override
    public BatchRemoveScalingInstancesResponse deleteInstances(List<String> instanceIds) {
        BatchRemoveScalingInstancesRequest request = buildBatchRemoveScalingInstancesRequest(instanceIds);
        LOG.info("batch remove instances begin, request={}", request);
        BatchRemoveScalingInstancesResponse resp = asClient.batchRemoveScalingInstances(request);
        LOG.info("batch remove instances end, resp={}", resp);
        SdkResponseAssertion.assertError(resp, "delete scaling group instance failed");
        return resp;
    }

    BatchRemoveScalingInstancesRequest buildBatchRemoveScalingInstancesRequest(List<String> instanceIds) {
        return new BatchRemoveScalingInstancesRequest().withScalingGroupId(asConfiguration.getGroup())
            .withBody(buildBatchRemoveInstancesOption(instanceIds));
    }

    BatchRemoveInstancesOption buildBatchRemoveInstancesOption(List<String> instanceIds) {
        return new BatchRemoveInstancesOption().withInstancesId(instanceIds)
            .withAction(BatchRemoveInstancesOption.ActionEnum.REMOVE)
            .withInstanceDelete(BatchRemoveInstancesOption.InstanceDeleteEnum.YES);
    }
}
